package com.dnb.webmash.playmaker.server;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheFactory;
import net.sf.jsr107cache.CacheManager;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.dnb.webmash.playmaker.client.WebPlaylistService;
import com.dnb.webmash.playmaker.shared.LoginInfo;
import com.dnb.webmash.playmaker.shared.MediaType;
import com.dnb.webmash.playmaker.shared.MyURL;
import com.dnb.webmash.playmaker.shared.PlayerConfig;
import com.dnb.webmash.playmaker.shared.PlayerType;
import com.dnb.webmash.playmaker.shared.PlaylistItem;
import com.dnb.webmash.playmaker.shared.Utility;
import com.dnb.webmash.playmaker.shared.playerconfigs.FlashSettings;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceException;
import com.google.appengine.api.memcache.stdimpl.GCacheFactory;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.apphosting.api.DeadlineExceededException;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

@SuppressWarnings("serial")
public class WebPlaylistServiceImpl extends RemoteServiceServlet implements 
WebPlaylistService {
	private String requestedURL;
	private static final String MEDIA_CONST = "Media";
	private static final String SITEMAP_CONST = "Sitemap";
	private static final String LINKS_CONST = "Links";
	
	//private static final Logger LOG = Logger.getLogger(WebPlaylistServiceImpl.class.getName()); //TODO USE IF NECESSARY FOR APP ENGINE SERVERSIDE LOGGING (viewable online)
	
	@Override
	public PlaylistItem requestPlaylist(String input, boolean enableRecursiveCrawling, int levels, Boolean mediaOnly, String requestID) throws IllegalArgumentException {
		String myReqID;//TODO CONT HERE SET THE NEXTLEVEL AND THE PARENTS
		// Verify that the input is valid. 
		if (!ServerFieldVerifier.isValidURL(input)) {
			// If the input is not valid, throw an IllegalArgumentException back to
			// the client.
			throw new IllegalArgumentException("Invalid MyURL");
		}
		else requestedURL = input.trim();
		
		//Add Root playlistitem node for the MyURL
		PlaylistItem root = new PlaylistItem(new MyURL(this.requestedURL));//HOLDS THE PLAYLIST			

		Document doc;
		try {							       
			LinkedHashSet<PlaylistItem> rootChildren = new LinkedHashSet<PlaylistItem>();

			PlaylistItem intLinks = new PlaylistItem(SITEMAP_CONST);	
			Set<PlaylistItem> internalLinks = new LinkedHashSet<PlaylistItem>(); //no duplicates makes for faster recursion
			PlaylistItem extLinks = new PlaylistItem(LINKS_CONST);				
			LinkedHashSet<PlaylistItem> externalLinks = new LinkedHashSet<PlaylistItem>(); //dont mind duplicates here
			PlaylistItem media = new PlaylistItem(MEDIA_CONST);			
			Set<PlaylistItem> mediaItems = new LinkedHashSet<PlaylistItem>(); //dont duplicate media, and sort according to added order

			Thread.currentThread();
			Thread.sleep(0);
			doc = Jsoup.connect(requestedURL).get();	//GET THE ENTIRE HTML OF THE PAGE AT THIS URL	

			//Get the links
			Elements links = doc.select("a[href]");
			for (Element link : links) {
				String linkHref = ServerFieldVerifier.cleanURL(link.attr("abs:href"));//clean the link to remove any arguments in the URL
				String linkText = link.text().trim();

				PlaylistItem f;
				if (!linkText.isEmpty())
					f = new PlaylistItem(new MyURL(linkHref), linkText);
				else f = new PlaylistItem(new MyURL(linkHref));

				String clean = ServerFieldVerifier.getBaseDomain(linkHref);
				if (ServerFieldVerifier.getBaseDomain(this.requestedURL).equals(clean))
					internalLinks.add(f);
				else
					externalLinks.add(f);
			}
			
			//GET THE KNOWN MEDIAS
			//Add all media items to media placeholder
			//**********************
			//TODO LOAD AND CACHE THE MEDIATYPES AND GENERICS LIST ONLY ONCE PER REQUEST ID
			ArrayList<MediaType> mediaTypes = MediaLibrary.getMediaTypes();
			for (int i =0; i < mediaTypes.size(); i++){
				if (doc.outerHtml().contains(mediaTypes.get(i).getTestPat())){
					mediaItems.addAll(PlaylistFromMediaTypes.addMediaItems(doc.outerHtml(), mediaTypes.get(i), requestedURL));
					}
			}
		
			//Get the GENERIC MEDIATYPES
			Elements objects;		
			ArrayList<MediaType> genHeur = MediaLibrary.getGenericTypes();
			for (MediaType g : genHeur){
				objects = doc.select(g.getTestPat());
				for (Element object : objects) {
					for (String s : g.getMediaIDPats()) {
						if (!object.select(s).isEmpty()){
							mediaItems.add(createGenMediaPlsItem(object, g));
						}
					}
				}			
			}
			//update the playlistitems from the lists
			intLinks.addChildren(new LinkedHashSet<PlaylistItem> (internalLinks));
			extLinks.addChildren(externalLinks);			
			media.addChildren(new LinkedHashSet<PlaylistItem> (mediaItems));								
			if (!mediaOnly){
				rootChildren.add(intLinks);
				rootChildren.add(extLinks);
			}
			if (media.hasChildren())
				rootChildren.add(media);
			if (!rootChildren.isEmpty())
				root.addChildren(rootChildren);
					
			//Ensure this request can be resumed			
			if (enableRecursiveCrawling){				
				ArrayList <PlaylistItem> values = new ArrayList<PlaylistItem>(internalLinks);
				ArrayList <PlaylistItem> approved = new ArrayList<PlaylistItem>();
				if (mediaOnly) values.addAll(externalLinks); 
				//go into all links when just looking for media recursively... otherwise its a sitemap request and we don't care about expanding external links
				if (!values.isEmpty()){
					if (requestID == null) //NEW REQUEST, requestID can be null on first iteration of recursion
						myReqID = Utility.generateRequestID();						
					else myReqID = requestID;
					this.cachePlsIt(root, myReqID);//if this is the first time this node is cached, it is first request (and now its cached)
					for (PlaylistItem child : values){
						if (child!=null){
							String childsURL = child.getFullURL();					
							if ((childsURL!=null)&&(child.getURL().compareTo(root.getURL())>0)){
								//make sure recursively entered links are subfolders of the root (longer URLs) 
								//HEURISTICS HERE	 				
								if (heuristicRecursionFilter(child)){														
									if (this.cacheIfNotAlready(child, myReqID))
										//TODO Store the visited URLS here... only go into recursion if wasnt already there
										approved.add(child);
									//else System.out.println("AlreadyCached= "+child);
								}
							}
						}
					}
					root.setNextLevel(approved); //set the nextlevel so this recursion request can be resumed
					//**********************MAIN HALF OF ENABLERECURSIVECRAWLING FINISHED>>> INTERNAL RECURSION NEXT
					if (levels>0){
						for (PlaylistItem child : approved){
							if (child!=null){
								String childsURL = child.getFullURL();	
								int nextLevel = levels-1;
								Thread.currentThread();
								Thread.sleep(0);//makes sure the request is timed properly
								PlaylistItem it = requestPlaylist(childsURL,true,nextLevel,mediaOnly, myReqID);									
								if (it!=null){
									it.setName(child.getName());
									if (!mediaOnly){
										if (it.hasChildren()){
											intLinks.removeChild(child);//disown the child that hasnt grandchildren
											intLinks.addChild(it);//adopt the child with children
										}
									}
									else {
										if (it.hasChildren()){
											LinkedHashSet<PlaylistItem> list = it.getChildren();
											for (PlaylistItem p : list){
												if (p.getName().equals(MEDIA_CONST)){
													media.addChildren(p.getChildren());															
												}
											}
										}
									}
								}else break; //TIMES UP!
							}
						}
						//update the playlistitems from the lists (only if we went into internal recursion)
						intLinks.addChildren(new LinkedHashSet<PlaylistItem> (internalLinks));
						extLinks.addChildren(externalLinks);
						media.addChildren(new LinkedHashSet<PlaylistItem> (mediaItems));								
						if (!mediaOnly){
							rootChildren.add(intLinks);
							rootChildren.add(extLinks);
						}
						if (media.hasChildren())
							rootChildren.add(media);
						if (!rootChildren.isEmpty())
							root.addChildren(rootChildren);
					}
				}
			}
		} catch (IllegalArgumentException e){
			GWT.log("MyURL is not absolute!",e);					
		} catch (MalformedURLException e){				
			GWT.log("MALFORMED MyURL!",e);
		} catch (SocketTimeoutException e){
			GWT.log("Connection timed out...",e);
		} catch (IOException e){
			GWT.log("READ/WRITE ERROR!",e);
		} catch (DeadlineExceededException e){
			return null;//avoid hard deadlines at all costs
		} catch (InterruptedException e) {
			return null;
		}
		return root;		
	}
	
	@Override
	public PlaylistItem resumeRecursion(PlaylistItem empty, Boolean mediaOnly, String requestID){
		PlaylistItem root;
		try {
			if (empty.getURL()!=null)
				root = new PlaylistItem(empty.getURL());//HOLDS THE PLAYLIST			
			else return null;
			
			//Copy or create new main nodes in root
			LinkedHashSet<PlaylistItem> emptyChildren = empty.getChildren();
			PlaylistItem intLinks = null, extLinks = null, media = null;		
			for (PlaylistItem r : emptyChildren){
				if (r.getName().equals(MEDIA_CONST))
					media = r;
				if (r.getName().equals(SITEMAP_CONST))
					intLinks = r;
				if (r.getName().equals(LINKS_CONST))
					extLinks = r;
			}
			if (media == null)
				media = new PlaylistItem(MEDIA_CONST);
			if (intLinks == null)
				intLinks = new PlaylistItem(SITEMAP_CONST);
			if (extLinks == null)
				extLinks = new PlaylistItem(LINKS_CONST);	
			 
			//try to resume at next level
			ArrayList<PlaylistItem> nextLevel = empty.getNextLevel();
			if (nextLevel!=null){
				PlaylistItem q;
				for (PlaylistItem p : nextLevel){
					if (ServerFieldVerifier.isValidURL(p.getFullURL())){ 
						Thread.currentThread();
						Thread.sleep(0);//makes sure the request is timed properly
						q = requestPlaylist(p.getFullURL(),true,0,mediaOnly,requestID);
						if (q==null) break; //TIMES UP
						root.setNextLevel(q.getNextLevel());//make sure to keep passing the buck
						if (q.hasChildren()){
							LinkedHashSet<PlaylistItem> list = q.getChildren();
							for (PlaylistItem r : list){ //add the main nodes
								if (r.getName().equals(MEDIA_CONST))
									media.addChildren(r.getChildren());
								if (r.getName().equals(SITEMAP_CONST))
									intLinks.addChildren(r.getChildren());
								if (r.getName().equals(LINKS_CONST))
									extLinks.addChildren(r.getChildren());
							}
						}//else System.out.println("Nothing found here: "+q);
					}
				}
				LinkedHashSet<PlaylistItem> rootChildren = new LinkedHashSet<PlaylistItem>();
						
				if (!mediaOnly){
					rootChildren.add(intLinks);
					rootChildren.add(extLinks);
				}
				if (media.hasChildren())
					rootChildren.add(media);
				if (!rootChildren.isEmpty())
					root.addChildren(rootChildren);
			}//else System.out.println("NULL NEXT LEVEL");
		} catch (InterruptedException e) {
			return null;
		}
		return root;
	}
	
	@Override
	public Boolean requestSaveUserPls(LinkedHashSet<PlaylistItem> pls, LoginInfo login){//TODO CLEAR PREVIOUS SAVED SESSION AND RESAVE
		PersistenceManager pm = PMF.get().getPersistenceManager();
        try {
        	// todo get all the lists from each level and store them
        	LinkedHashSet<PlaylistItem> store = new LinkedHashSet<PlaylistItem>();
        	if (login.getUniqueID() != null) {
        		// DELETE PREVIOUS SESSION FIRST        		 
    			Query q = pm.newQuery(PlaylistItem.class, "owner == u");
	    		q.declareParameters("com.google.appengine.api.users.User u");
	    		q.setOrdering("createDate ascending");	    		
        		@SuppressWarnings("unchecked")
    			List<PlaylistItem> playlists = (List<PlaylistItem>) q.execute(login.getUniqueID());
        		pm.deletePersistentAll(playlists);
            	
            	// NOW SAVE NEW ONE
        		//flatten first
        		for (PlaylistItem p : pls){        			
        			store.add(p);
        			if (p.hasChildren())
        				store.addAll(getChildrenFlat(pls));        			
        		}
        		//now take ownership
        		for (PlaylistItem p : store)
        			p.setOwner(login.getUniqueID());
        		//and send to datastore
    			pm.makePersistentAll(store);
        	} else {
        		GWT.log("NULL USER - CANT SAVE PLAYLIST");
        		return new Boolean(false);
        	}
        } finally {
            pm.close();
        }
        //TODO ADD VERIFICATION THAT SAVING WORKED
        return new Boolean(true);        
	}
	
	@Override
	public PlaylistItem requestLoadCurUserPls() {
		UserService userService = UserServiceFactory.getUserService();
	    String userID = userService.getCurrentUser().getUserId();
	    if (userID!=null){
	    	return requestLoadPlsHelper(userID, "LoadedPreviousSession");
	    }
	    else
	    	return null;		//TODO deal with an invalid load request when user is not logged in
	}
	@Override
	public PlaylistItem requestLoadGlobalPls() {
	    return requestLoadPlsHelper("global", "WhatEveryoneIsWatching");//TODO needs limits to # of results, cleanup, top10?
	}
	public ArrayList<PlaylistItem> requestLoadPls(ArrayList<String> request){
		ArrayList<PlaylistItem> result = new ArrayList<PlaylistItem>();
		for (String r : request){
			result.add(this.requestLoadPlsHelper(r, r));
		}
		return result;
	}
	@Override
	public ArrayList<MediaType> requestAllPlayTypes() {
		return MediaLibrary.getAllTypes();
	}
	@Override
	public PlayerConfig requestDefaultConfigs(PlayerType type) {
		// TODO IMPLEMENT PROPERLY ... USE MEDIALIBRARY to list all pref types (have to change it a little due to MediaType hardcoded in there)
		// then cycle all the pref types and return matching one
		
		//TESTING
		if (type == PlayerType.FLASH){
			PlayerConfig result = new FlashSettings();
			return result;
		}
		else
			return null;
	}
	@Override
	public PlayerConfig requestLoadUserConfigs(PlayerType type) {//IF NOTHING TO LOAD RETURN DEFAULTS
		// TODO IMPLEMENT!
		
		//TESTING
		return this.requestDefaultConfigs(type);
	}
	
	@Override
	public Boolean storeIfNotAlready(ArrayList<PlaylistItem> plsToStore, String name) {
		boolean storedSomething = false;
		if (name!=null) //store the requested URL
			storedSomething = storeIfNotAlready(new PlaylistItem(new MyURL(name)),"global");
		for (PlaylistItem p : plsToStore){			
			storedSomething = storeIfNotAlready(p,p.getMediatype());//STORE TO SELF OWNERSHIP... mediatype name owns it
		}
		return storedSomething;
	}
	
	@Override //TODO USE THIS >>> CONTINUE HERE
	public boolean requestCreateNewMedia(MediaType nT) {//TODO ERROR CATCHING... PREVENT GARBAGE?
		if (nT!=null){
			String owner = new String("Media");
			PersistenceManager pm = PMF.get().getPersistenceManager();
			boolean result = false;
			try {
    			nT.setOwner(owner);//TODO add adult filters here? store to different owner.		
    			pm.makePersistent(nT);
    			result = true;
			} finally {
	    		pm.close();
	    	}
			return result;
		}
		else return false;
	}
	
	/****************************************************************************************************************
	 * END OF RPC Methods
	 * Start of Helpers
	 ****************************************************************************************************************/
	@SuppressWarnings("unchecked")
	public PlaylistItem requestLoadPlsHelper(String user, String nodeName) {
		if (!user.equals(null)){					
			LinkedHashSet<PlaylistItem> result = new LinkedHashSet<PlaylistItem>();
	    	PersistenceManager pm = PMF.get().getPersistenceManager();
	    	try {	    		
	    		Query q = pm.newQuery(PlaylistItem.class, "owner == u");
	    		q.declareParameters("com.google.appengine.api.users.User u");
	    		q.setOrdering("createDate ascending");	    		
	    		List<PlaylistItem> playlists = (List<PlaylistItem>) q.execute(user);
	    		for (PlaylistItem pls : playlists) {
	    			if ((pls!=null)&&(!pls.isSkeleton()))//DON'T LOAD GARBAGE
	    					result.add(pls);
	    		}
	    	} finally {
	    		pm.close();
	    	}
	    	PlaylistItem loadedNode = new PlaylistItem(new MyURL(nodeName), nodeName);
	    	//give it a URL so it is considered Unique TODO FIX THIS HACK
	    	loadedNode.setOwner(user);
	    	loadedNode.addChildren(result);
	    	return loadedNode;
		}
		else return null;
	}
	//returns true if it performed a makepersistent operation (if it made a change to jdo)
	private boolean storeIfNotAlready(PlaylistItem plsToStore, String owner){
		//Store every requested URL if not already there
		PersistenceManager pm = PMF.get().getPersistenceManager();
		boolean result = false;
		try {
    		Query q = pm.newQuery(PlaylistItem.class);
    		//q.setFilter("myURL.myValue == m && owner == u");
    		q.setFilter("owner == u && (myURL.myValue.contains(m) || m.contains(myURL.myValue))");
    		q.declareParameters("String m, com.google.appengine.api.users.User u");
    		q.setOrdering("createDate ascending");	
			@SuppressWarnings("unchecked")
			List<PlaylistItem> playlists = (List<PlaylistItem>) q.execute(plsToStore.getFullURL(), owner);
			if (playlists.isEmpty()){
				result = true;    			
    			plsToStore.setOwner(owner);//TODO add adult filters here? store to different owner.		
    			pm.makePersistent(plsToStore);
    		}
			else result = false;
		} finally {
    		pm.close();
    	}
		return result;
	}
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private boolean cacheIfNotAlready(PlaylistItem storeRoot, String owner){
		try {
			Cache cache;
	        Map props = new HashMap();
	        props.put(GCacheFactory.EXPIRATION_DELTA, 3600); //Hardcoded one hour cache lifetime
	        props.put(MemcacheService.SetPolicy.SET_ALWAYS, true);       
	        
            CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
            cache = cacheFactory.createCache(props);
            String url = storeRoot.getFullURL();
            
            if (cache.containsKey(url)){
            	ArrayList<String> requestors = (ArrayList<String>)cache.get(url);
            	if (requestors.contains(owner))
            		return false;
            	else {
            		requestors.add(owner);
            		cache.put(url, requestors);
            		return true;
            	}
            }
            else {cache.put(url, new ArrayList<String>(Arrays.asList(owner)));
            	return true;
            }
        } catch (CacheException e) {
        	//System.out.println("CACHING ERROR 1 = " + e);
            return true;//IGNORE CACHE ERRORS
        } catch (MemcacheServiceException e){
        	//System.out.println("CACHING ERROR 2 = " + e);
        	return true;//IGNORE CACHE ERRORS
        }
	}
	@SuppressWarnings({ "unchecked", "rawtypes" })
	private boolean cachePlsIt(PlaylistItem storeRoot, String owner){
		try {
			Cache cache;
	        Map props = new HashMap();
	        props.put(GCacheFactory.EXPIRATION_DELTA, 3600); //Hardcoded one hour cache lifetime
	        props.put(MemcacheService.SetPolicy.SET_ALWAYS, true);       
	        
            CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
            cache = cacheFactory.createCache(props);
            String url = storeRoot.getFullURL();
            
            cache.put(url, new ArrayList<String>(Arrays.asList(owner)));
            return true;
        } catch (CacheException e) {
            return false;//WAS UNABLE TO CACHE
        } catch (MemcacheServiceException e){
        	return false;
        }
	}
	
	private PlaylistItem createGenMediaPlsItem(Element object, MediaType type) {
		String url = this.findURL(object);
		String html = object.outerHtml();
		PlaylistItem f = new PlaylistItem(new MyURL(url));
		f.setElement(html);					  
		f.setMediatype(type.getName());
		f.setPlayerType(type.getPlayerType());
		f.setPlayable(true);
		return f;
	}
	private String findURL(Element object) {
		Elements els = object.getAllElements();
		for (Element el : els){
			Attributes attr = el.attributes();
			for (Attribute att : attr)
			{				if (ServerFieldVerifier.isValidURL(att.getValue())) return att.getValue();
			}		
		}		
		return object.baseUri();//TODO find some better alternative?
	}
	
	//recursively flattens a playlist
	private LinkedHashSet<PlaylistItem> getChildrenFlat( LinkedHashSet<PlaylistItem> pls) {
		LinkedHashSet <PlaylistItem> result = new LinkedHashSet <PlaylistItem>();
		for (PlaylistItem p : pls){
			result.add(p);
			if (p.hasChildren())			
				result.addAll(getChildrenFlat(p.getChildren()));							
		}
		return result;
	}
	
	//TODO CREATE UI FOR THIS??
	private boolean heuristicRecursionFilter(PlaylistItem child) {
		//Check for eliminating factors first
		if (child.isPlayable()) return false; //dont need to go further here
		if (child.isSkeleton()) return false; //nothing here		
		if (child.getFullURL().contains("#")) return false; //no inline links
		//	TODO Adult filters here
		//URL FILTERS HERE //TODO EXTRACT THESE AND MAKE UI		
		if (child.hasChildren()) return true; //dont cut off branches, only leaves
		if ((child.getFullURL().toLowerCase().contains("media")) || (child.getFullURL().toLowerCase().contains("movie")) || 
			(child.getFullURL().toLowerCase().contains("video")) || (child.getFullURL().toLowerCase().contains("show")) ||
			(child.getFullURL().toLowerCase().contains("view")) || (child.getFullURL().toLowerCase().contains("embed")) ||
			(child.getFullURL().toLowerCase().contains("stream")) || (child.getFullURL().toLowerCase().contains("1")) ||
			(child.getFullURL().toLowerCase().contains("2")) || (child.getFullURL().toLowerCase().contains("3")) || 
			(child.getFullURL().toLowerCase().contains("4")) || (child.getFullURL().toLowerCase().contains("5")) || 
			(child.getFullURL().toLowerCase().contains("6")) || (child.getFullURL().toLowerCase().contains("7")) || 
			(child.getFullURL().toLowerCase().contains("8")) || (child.getFullURL().toLowerCase().contains("9")) ||
			(child.getFullURL().toLowerCase().contains("0")) || (child.getFullURL().toLowerCase().contains("watch")) ||
			(child.getFullURL().toLowerCase().contains("season")) || (child.getFullURL().toLowerCase().contains("episode")) ||
			(child.getFullURL().toLowerCase().contains("music")) || (child.getFullURL().toLowerCase().contains(".avi")) ||
			(child.getFullURL().toLowerCase().contains(".mpg")) || (child.getFullURL().toLowerCase().contains(".mpeg")) ||
			(child.getFullURL().toLowerCase().contains(".mp3")) || (child.getFullURL().toLowerCase().contains(".mp4")) ||
			(child.getFullURL().toLowerCase().contains(".mov")) || (child.getFullURL().toLowerCase().contains("flash")) ||
			(child.getFullURL().toLowerCase().contains(".rm")) || (child.getFullURL().toLowerCase().contains(".wmv")) ||			
			(child.getFullURL().toLowerCase().contains("photo")) ||(child.getFullURL().toLowerCase().contains("display")))
			// TODO TEST AND ADD MORE?
			//TODO ADD ANY DATE
			return true;
		
		
		//DEFAULT TO TRUE
		return true;
	}

}
